﻿using System;
using System.Text;
using System.IO;
using System.Security.Cryptography;

/*
     分段RSA加解密， 来自网络，适当修改
    * 
    * 张鹏
    * 
    * 2016.5

    */
public static class RSACrypto
{
    private static readonly Encoding Encoder = Encoding.UTF8;

    public const string rsa_public_key = @"<RSAKeyValue>
      <Modulus>5m9m14XH3oqLJ8bNGw9e4rGpXpcktv9MSkHSVFVMjHbfv+SJ5v0ubqQxa5YjLN4vc49z7SVju8s0X4gZ6AzZTn06jzWOgyPRV54Q4I0DCYadWW4Ze3e+BOtwgVU1Og3qHKn8vygoj40J6U85Z/PTJu3hN1m75Zr195ju7g9v4Hk=</Modulus>
      <Exponent>AQAB</Exponent>
</RSAKeyValue>";
    public const string rsa_private_key = @"<RSAKeyValue><Modulus>5m9m14XH3oqLJ8bNGw9e4rGpXpcktv9MSkHSVFVMjHbfv+SJ5v0ubqQxa5YjLN4vc49z7SVju8s0X4gZ6AzZTn06jzWOgyPRV54Q4I0DCYadWW4Ze3e+BOtwgVU1Og3qHKn8vygoj40J6U85Z/PTJu3hN1m75Zr195ju7g9v4Hk=</Modulus><Exponent>AQAB</Exponent><P>/hf2dnK7rNfl3lbqghWcpFdu778hUpIEBixCDL5WiBtpkZdpSw90aERmHJYaW2RGvGRi6zSftLh00KHsPcNUMw==</P><Q>6Cn/jOLrPapDTEp1Fkq+uz++1Do0eeX7HYqi9rY29CqShzCeI7LEYOoSwYuAJ3xA/DuCdQENPSoJ9KFbO4Wsow==</Q><DP>ga1rHIJro8e/yhxjrKYo/nqc5ICQGhrpMNlPkD9n3CjZVPOISkWF7FzUHEzDANeJfkZhcZa21z24aG3rKo5Qnw==</DP><DQ>MNGsCB8rYlMsRZ2ek2pyQwO7h/sZT8y5ilO9wu08Dwnot/7UMiOEQfDWstY3w5XQQHnvC9WFyCfP4h4QBissyw==</DQ><InverseQ>EG02S7SADhH1EVT9DD0Z62Y0uY7gIYvxX/uq+IzKSCwB8M2G7Qv9xgZQaQlLpCaeKbux3Y59hHM+KpamGL19Kg==</InverseQ><D>vmaYHEbPAgOJvaEXQl+t8DQKFT1fudEysTy31LTyXjGu6XiltXXHUuZaa2IPyHgBz0Nd7znwsW/S44iql0Fen1kzKioEL3svANui63O3o5xdDeExVM6zOf1wUUh/oldovPweChyoAdMtUzgvCbJk1sYDJf++Nr0FeNW1RB1XG30=</D></RSAKeyValue>";

    /// <summary>
    /// RSA加密
    /// </summary>
    /// <param name="plaintext"></param>
    /// <param name="public_key"></param>
    /// <returns></returns>
    public static String Encrypt(this String plaintext, string public_key)
    {
        using (RSACryptoServiceProvider RSACryptography = new RSACryptoServiceProvider())
        {
            RSACryptography.FromXmlString(public_key);

            Byte[] PlaintextData = RSACrypto.Encoder.GetBytes(plaintext);
            int MaxBlockSize = RSACryptography.KeySize / 8 - 11;    //加密块最大长度限制

            if (PlaintextData.Length <= MaxBlockSize)
                return Convert.ToBase64String(RSACryptography.Encrypt(PlaintextData, false));

            using (MemoryStream PlaiStream = new MemoryStream(PlaintextData))
            using (MemoryStream CrypStream = new MemoryStream())
            {
                Byte[] Buffer = new Byte[MaxBlockSize];
                int BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize);

                while (BlockSize > 0)
                {
                    Byte[] ToEncrypt = new Byte[BlockSize];
                    Array.Copy(Buffer, 0, ToEncrypt, 0, BlockSize);

                    Byte[] Cryptograph = RSACryptography.Encrypt(ToEncrypt, false);
                    CrypStream.Write(Cryptograph, 0, Cryptograph.Length);

                    BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize);
                }

                return Convert.ToBase64String(CrypStream.ToArray(), Base64FormattingOptions.None);
            }
        }
    }

    /// <summary>
    /// RSA解密
    /// </summary>
    /// <param name="ciphertext"></param>
    /// <param name="private_key"></param>
    /// <returns></returns>
    public static String Decrypt(this String ciphertext, string private_key)
    {
        using (RSACryptoServiceProvider RSACryptography = new RSACryptoServiceProvider())
        {
            RSACryptography.FromXmlString(private_key);

            Byte[] CiphertextData = Convert.FromBase64String(ciphertext);
            int MaxBlockSize = RSACryptography.KeySize / 8;    //解密块最大长度限制

            if (CiphertextData.Length <= MaxBlockSize)
                return RSACrypto.Encoder.GetString(RSACryptography.Decrypt(CiphertextData, false));

            using (MemoryStream CrypStream = new MemoryStream(CiphertextData))
            using (MemoryStream PlaiStream = new MemoryStream())
            {
                Byte[] Buffer = new Byte[MaxBlockSize];
                int BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize);

                while (BlockSize > 0)
                {
                    Byte[] ToDecrypt = new Byte[BlockSize];
                    Array.Copy(Buffer, 0, ToDecrypt, 0, BlockSize);

                    Byte[] Plaintext = RSACryptography.Decrypt(ToDecrypt, false);
                    PlaiStream.Write(Plaintext, 0, Plaintext.Length);

                    BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize);
                }

                return RSACrypto.Encoder.GetString(PlaiStream.ToArray());
            }
        }
    }


    public static byte[] Encrypt(byte[] source, string public_key)
    {

        using (RSACryptoServiceProvider RSACryptography = new RSACryptoServiceProvider())
        {
            RSACryptography.FromXmlString(public_key);


            int MaxBlockSize = RSACryptography.KeySize / 8 - 11;    //加密块最大长度限制

            if (source.Length <= MaxBlockSize)
                return RSACryptography.Encrypt(source, false);

            using (MemoryStream PlaiStream = new MemoryStream(source))
            using (MemoryStream CrypStream = new MemoryStream())
            {
                Byte[] Buffer = new Byte[MaxBlockSize];
                int BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize);

                while (BlockSize > 0)
                {
                    Byte[] ToEncrypt = new Byte[BlockSize];
                    Array.Copy(Buffer, 0, ToEncrypt, 0, BlockSize);

                    Byte[] Cryptograph = RSACryptography.Encrypt(ToEncrypt, false);
                    CrypStream.Write(Cryptograph, 0, Cryptograph.Length);

                    BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize);
                }

                return CrypStream.ToArray();
            }
        }

    }

    public static byte[] Decrypt(byte[] source, string private_key)
    {
        using (RSACryptoServiceProvider RSACryptography = new RSACryptoServiceProvider())
        {
            RSACryptography.FromXmlString(private_key);


            int MaxBlockSize = RSACryptography.KeySize / 8;    //解密块最大长度限制

            if (source.Length <= MaxBlockSize)
                return RSACryptography.Decrypt(source, false);

            using (MemoryStream CrypStream = new MemoryStream(source))
            using (MemoryStream PlaiStream = new MemoryStream())
            {
                Byte[] Buffer = new Byte[MaxBlockSize];
                int BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize);

                while (BlockSize > 0)
                {
                    Byte[] ToDecrypt = new Byte[BlockSize];
                    Array.Copy(Buffer, 0, ToDecrypt, 0, BlockSize);

                    Byte[] Plaintext = RSACryptography.Decrypt(ToDecrypt, false);
                    PlaiStream.Write(Plaintext, 0, Plaintext.Length);

                    BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize);
                }

                return PlaiStream.ToArray();
            }
        }
    }
}
